Okay.
So today we're going to have a look at data stores.
Now data stores are again think I said this for quite a lot of things.
But I think they're really cool and they're essential for um 99% of games your data is one going to
want to be saved if the player just if a player joins your game, they play for hours, they leave and
then join again and they find out all that progress has been gone and there's really no point for them
to continue playing a game.
So it's something that's absolutely essential for all games.
And it's quite simple as well.
You'd think in order to save data and keep it somewhere when the player joins again, it'd be quite
complicated, but it's a nice handy service that does all the behind the scenes work for it.
So, um, we scriptures don't have to do that much.
So this is done on on the server so on as a client nets on the server.
So add a script into server script service here.
Okay.
So um.
Data stores.
In order to use a data store, you need access data store service.
This is a service containing all the information to do of data stored.
It's not.
It's not accessible by default, so you need to access it just in the same way you'd access twin service
or use input service.
So local data store.
Service is equal to game.
Get service data store service like that there.
And we also need to fetch the data data store.
Okay.
Now this is where we need to fetch basically where our data is saved.
And this is saved in a data store.
So we need to get that.
So we need to say local data store.
Is equal to datastore.
Service.
Colon.
Get.
Datastore.
Okay.
And it will fetch a datastore with any given name.
We're going to call this just datastore.
Just like that.
And that'll be completely fine for you to use as well.
Okay.
This is the name of your datastore.
Okay.
So, um, there are two parts to this.
The first part is about saving data when the player leaves.
Um, well, if you think about it chronologically, it's the first part, but it's the second part that
we code.
So, um.
Yeah, basically, when the player leaves, we're wanting to save their data.
And when the player joins, we're wanting to get their save data and apply it to whatever, whatever
values they have at the moment.
Okay.
So, um, I think it might make a bit more sense if we start by coding the bit when the player leaves
and then going and coding with the when the player joins probably.
Yeah.
Okay.
So let's code that bit.
So we know we can detect when the player leaves by using the um player removing event.
So we're going to use that which contains a parameter containing the player.
Okay.
So um when the player leaves we basically need to um.
No, sorry.
Um.
Yes, it.
Okay.
So it depends how you set this up in your game.
We've looked at Leaderstats already.
If you have a leaderstats system already active, you could code it in this way.
Um, but sometimes people prefer to use the Leaderstats create the Leaderstats system in their data
store, which is the most useful way to do it, really?
I'm not going to do it.
I'm going to do that bit second.
I know it makes a bit more sense when you think about it to code a bit when when they remove and then
when they join first, but because when they, when they join we need to add values into the leaderboard.
We do have to start it off with play.
I don't know why it chose to do it in a weird, weird way way for that one.
Um, but yeah.
Okay, so player added Kinect function player.
Okay, so when the player joins we first off we just do all the standard leaderstats stuff we already
know.
Okay, so this is making a Leaderstats folder inside, um, the player.
Like say leaderstats dot parents is equal to player.
And then obviously leaderstats dot name is equal to that lowercase l leaderstats very important there.
Okay.
And then you want to add into the leaderboard the value you're wanting to save.
Now this is optional.
You don't necessarily have to add it into the leaderboard.
But for most currency systems like coins cash, diamonds you're going to want it in the leaderboard
as well.
So local cash for example is equal to instance dot new integer value.
If you're a bit confused on this, take a look at the values lesson we did a while ago as it explain
about how to do leaderstats cash dot parents is equal to.
Leaderstats.
I don't know why I am making so many mistakes typing today.
Cash dot name is equal to cash.
Like that's fair.
And yeah, if you are wanting to save a value which doesn't appear on the leaderboard, add it in normally
and I'd recommend just making a second folder inside of the player called Player Values.
And that can contain basic values like I don't know, has the player spun their daily reward yet but
for the day or stuff like that?
Really?
Okay.
Um, cool.
So now this is done, we, um, want to have a go at fetching or gonna go have a go at.
Yeah, fetching the data that was stored now, um, they might not they might not necessarily be data
already there because if it's their first time joining, there won't be data already saved in a data
store because they wouldn't have been able to save it because they haven't got any data.
So just to make sure that if there isn't any data, it doesn't do any weird things, we're going to
set local cache data to equal nil.
Okay.
This basically means that if there's nothing we can fetch, it's been set to nil by default.
So there won't be any data.
Remember nil just means nothing.
Okay, now this next bit is probably the most advanced bit of well, yeah, it definitely is the most
advanced bit of this code, which throws a lot of people off.
Um, and this is how we fetch the data.
Now, fetching the data is nice and easy.
Okay.
We will just set the cached data to equal and the data store.
And we make we equal to a function called get async.
And this function will basically return um any data store and any, any data stored in the data store.
I hope that makes sense.
Um, bit of a tongue twister.
Um, so in here, you want to write down the key.
Now your data store has certain keys which have unique stores of the data.
Now, um, the key basically consists of something which can uniquely identify the player along with
what was saved.
So in this case, you want to use a player's user ID and a little tag next to it.
Just saying cache.
The reason why we don't want to say the player's name player name can change and a bit more difficult
to handle, which is why we use a user id so player dot user id like that there, and then concatenate
it with cache just so we can separate cache.
And obviously if you had, if you had a couple of E's, you want to do this multiple times.
So that's not necessarily the issue.
Um, however, um, the issue with what we have here is that data stores are not 100% reliable.
They do.
Stores can go down quite frequently, um, for a few minutes or a few hours for maintenance by Roblox.
Okay.
Um, which is a bit of an issue for us because if we're not able to, um, get the data stored, if
we're not able to get the data in the data store, or we're not able to save our data, what are we
supposed to do now if we just left it as this, this would throw an error because we can't fetch this.
This function here wouldn't work because we can't fetch it from a data store, because it's because
it's not active.
It's it's temporarily down for maintenance and stuff like that.
Um, so we have to basically use something which means, um, which basically prevents an error being
thrown out.
Obviously, if the data store is down, we need to run some code to handle that.
But the idea is we don't want it to throw an error because if our data storing script frozen ever,
um, that means that player has been lost.
Bad data, which I don't think been very they're going to be very happy.
Happy about.
So we have to use a function type called a p call.
And I think stuff like that, I'm going to write out first and then I'll explain what it means as um,
it'll probably make more sense if you can see it visually.
So local success comma error error message.
Is equal to P call.
Function.
Now, this is probably confused you a bit because there's lots of weird things going on here.
We have a variable with two names.
We have a new term called a call with a function and somehow made this variable a function.
So lots of things here to mention about um, so let me explain it.
So a call, all it is, is just a type of function.
But what's special about the call is that if the function was not successful in doing what it needs
to do, it will not throw an error.
Instead, it will return an error message telling us what went wrong.
But if it was successful, then it would just it would just return success.
That's why we give it two values, because if it all went okay, it would return success.
If not, it will.
It will not return it because it's a success and it will instead give us an error message on what went
wrong, which is really essential for data stores.
So, um, a unique bit of code there, but hopefully that makes sense.
What it does.
Let's then put our code inside of here.
And now don't get me wrong, you can absolutely do this without a call, but it does risk players data
being lost.
So if you want to take that risk, sure don't do it.
But I'd highly recommend that you would.
Okay.
Um, cool.
So, um, let's then handle this.
So, um, if it managed to find the data.
Correct.
Now, even if there is no data in the data store, it will still return success because it was still
able to access it and find that there was no data.
It will only not print success if it wasn't able to reach the data store.
So if it was a success, we can then just set the value of cast of of this cache integer value to be
whatever cache data it found, as this would just be a number with the amount of cash that that player
had.
So if it's success cash dot value.
Is equal to cash data like that.
So the value of our cash integer is equal to the amount of data that it got in the data store.
Now let's say that it wasn't a success.
It wasn't a success.
It doesn't return success.
Instead it returned an error message.
Then all we can do is just warn that error message in the output.
Now, if you had a now, we're probably the better way to do this would probably be to, um, kind of.
Yeah.
If you wanted, if you wanted to do this in a proper way, you would, um, have a in your game, you'd
have a, um, text label, which basically would um.
Say something like if it would basically it would have some set responses to different error messages.
So let's say if the error message was like the code for, I don't know, the data store having maintenance
done to it, then it would, it would put that on the text labels.
The player can see it something like they'd stores are currently maintenance should only be a few minutes.
Please don't leave or your data won't be saved.
Something like that to easily tell the player look, there's stuff going on with data stores.
You should try not to try not to leave a game.
Okay, um, so that's basically how you'd properly handle it.
We're not going to do that.
This is just a simple data store.
But definitely maybe after this lesson have a look and see some applications of that.
Okay.
And that's everything you need to do when the player joins you need to add in some values, check what
data they currently have, add it in if they have it and not said wait there, sorry, warn and add.
Um.
Let yourself know if there's any issues.
Now we want to go on to the um bit when a player leaves, which is basically the same or it's very similar.
So game players dot player removing in this case um connect function player.
Like that fair.
And we want to basically save a data.
Um, so we want to say, um, we're going to make quite another pico because again, if the data store
is down so we can't save that data, we want to do something about it and not just be thrown an error.
Common error message.
Is equal to p.
Call function like that fair.
And we want to basically say datastore colon get async.
So we're getting the datastore and we want to save it.
So we're saving it by writing down the key to start off with.
So player dot user ID then writing a also and then doing a little tag.
So.
Cash like that there.
And then we want to say what actual data we're wanting to store, which in this case would be the player
dot leader stats.
Dot cash dot value to save that cash value.
Okay.
And again same kind of stuff.
If it was if it was a success.
Um, we don't actually need to do anything.
So the only thing we need to check is not success, because there's no point saying anything like,
oh, your data was successfully saved because the players leaving.
Because we're not going to be able to see, um, see that message.
So no need to do that.
Um, if it's not, if it's not a success, all we need to do is just warn, um, that error message
listed there.
Okay.
And, um, that's pretty much it, but you need to do, um, so quite a bit of code and some new kind
of code you might not have seen before.
So hopefully you are all on the same page as what I'm saying here.
But, um, it's definitely a lot shorter than what you might have imagined for being able to save and
load data out.
Okay, now I'm going to try this out.
Now, I don't believe this will work.
First time, um, basically, because I haven't published this game.
So.
Yeah.
Oh no.
A complete error here.
So it didn't work, but luckily it gives us a reason in the output.
So there's 502 API services.
Rejected request with error error code seven reason studio access to APIs is not allowed.
This is simple to fix.
It's just a um, setting in game settings.
So go over to Game Settings.
Um, go over to security and you want to enable unique toggle on Enable Studio Access to services.
This enables studio access to game services such as data stores.
Turn that on and click save.
Try this out again.
It would probably give me another error saying you need to publish it unless I have published this game.
I don't think I have.
Um, okay, let's go into the leader starts.
And change the cash to five and let's leave the game.
It must have worked.
Then I must publish this game already.
Um.
Let me see.
File.
Publish.
Has already been published.
It must have been published then.
Okay.
That's cool.
So yeah, it works.
Now, if I go ahead and rejoin the game and take a look at the leaderboard.
Um, I will have zero cash and not five cash.
Why?
Well, data stores only work when actually playing the game.
They do not work when you're testing it in studio, basically, because, um.
The date still isn't set up correctly in the studio.
It's just a test kind of way to test out your game.
Um, because once you leave, you leave the server close as well.
But in a normal game, that wouldn't occur, so it all should be fine.
So feel free to publish it and try it out in your own game to make sure this works.
But yeah, this is the code for it here.
Um, but yeah, that's pretty much it about data doors.
Okay.
So hope you enjoyed this.
And it's a really, really useful addition you can make to your games to, to really make the players
want to come back to your game and play again basically.
Okay.
So hope you enjoyed this.
And next lesson we're going to have a look at another service called Context Action Service.
We'll have a look all about that in the next lecture.
So join me then.